import numpy as np
import matplotlib.pyplot as plt
import streamlit as st

plt.rcParams["font.sans-serif"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False


def sigmoid_run():
    def sigmoid(x):
        return 1 / (1 + np.exp(-x))

    def d_sigmoid(x):
        return sigmoid(x) * (1 - sigmoid(x))

    """ 进行画图 """
    x = np.linspace(-5, 5, 100)
    y = sigmoid(x)
    dy = d_sigmoid(x)
    plt.subplot(121)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.yticks(np.arange(0, 1.1, 0.1))
    plt.ylim(0, 1)
    plt.plot(x, y)
    plt.plot([0, 0], [0, 1], color="black", linewidth="2")

    plt.subplot(122)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.yticks(np.arange(0, 1.1, 0.1))
    plt.ylim(0, 1)
    plt.plot(x, dy)
    plt.plot([0, 0], [0, 1], color="black", linewidth="2")

    # plt.show()
    st.pyplot(plt)


def tanh_run():
    def tanh(x):
        # return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
        return np.tanh(x)

    def d_tanh(x):
        return 1 - np.square(tanh(x))

    """ 进行画图 """
    x = np.linspace(-5, 5, 100)
    y = tanh(x)
    dy = d_tanh(x)
    plt.subplot(121)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.yticks(np.arange(-1, 1.1, 0.1))
    plt.ylim(-1, 1)
    plt.plot(x, y)
    plt.plot([0, 0], [-1, 1], color="black", linewidth="2")

    plt.subplot(122)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.yticks(np.arange(0, 1.1, 0.1))
    plt.ylim(0, 1)
    plt.plot(x, dy)
    plt.plot([0, 0], [0, 1], color="black", linewidth="2")

    # plt.show()
    st.pyplot(plt)


def relu_run():
    # 定义两种ReLU函数
    def linear_relu(x):
        """线性ReLU：x≥0时输出x，x<0时输出0"""
        return np.maximum(0, x)

    def binary_relu(x, threshold=0):
        """二值化ReLU：x>threshold时输出1，否则输出0"""
        return np.where(x > threshold, 1, 0)

    # 生成输入数据
    x = np.linspace(-3, 3, 1000)  # 输入范围：-3到3
    y_linear = linear_relu(x)
    y_binary = binary_relu(x)

    # 创建画布和子图（1行2列布局）
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

    # 绘制左侧：线性ReLU
    ax1.plot(x, y_linear, color='royalblue', linewidth=2.5)
    ax1.axhline(y=0, color='gray', linestyle='--', alpha=0.5)
    ax1.axvline(x=0, color='gray', linestyle='--', alpha=0.5)
    ax1.set_title('线性ReLU函数', fontsize=15)
    ax1.set_xlabel('输入 x', fontsize=12)
    ax1.set_ylabel('输出 y', fontsize=12)
    ax1.set_ylim(-0.5, 3.5)  # 调整y轴范围，便于观察
    ax1.grid(True, alpha=0.3)
    ax1.text(1, 2.5, r'$y = \max(0, x)$', fontsize=14, color='royalblue')

    # 绘制右侧：二值化ReLU
    ax2.step(x, y_binary, color='crimson', linewidth=2.5, where='post')
    ax2.axhline(y=0, color='gray', linestyle='--', alpha=0.5)
    ax2.axvline(x=0, color='gray', linestyle='--', alpha=0.5)
    ax2.set_title('二值化ReLU函数', fontsize=15)
    ax2.set_xlabel('输入 x', fontsize=12)
    ax2.set_ylabel('输出 y', fontsize=12)
    ax2.set_ylim(-0.5, 1.5)  # 调整y轴范围，便于观察
    ax2.grid(True, alpha=0.3)
    ax2.text(1, 1.2, r'$y = 1\ \text{if}\ x>0,\ \text{else}\ 0$', fontsize=14, color='crimson')

    # 调整布局并显示
    plt.tight_layout()
    # plt.show()
    st.pyplot(fig)


def elu_run():
    # 定义 ELU 函数
    def elu(x, alpha=1.0):
        return np.where(x >= 0, x, alpha * (np.exp(x) - 1))

    # 定义 ELU 导数
    def elu_derivative(x, alpha=1.0):
        return np.where(x >= 0, 1, alpha * np.exp(x))

    # 生成数据
    x = np.linspace(-10, 10, 1000)
    y_elu = elu(x)
    y_deriv = elu_derivative(x)

    # 创建并排子图（1 行 2 列）
    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))  # 调整 figsize 控制整体大小

    # 绘制 ELU 函数（上图）
    ax1.plot(x, y_elu, color='blue', label='elu')
    ax1.set_title('elu')
    ax1.set_xlabel('x')
    ax1.set_ylabel('y')
    ax1.grid(True, linestyle='--', alpha=0.7)  # 显示网格
    ax1.legend()
    ax1.set_ylim(-2, 10)  # 调整 y 轴范围匹配示例

    # 绘制 ELU 导数（下图）
    ax2.plot(x, y_deriv, color='blue', label='elu_derivative')
    ax2.set_title('elu derivative')
    ax2.set_xlabel('x')
    ax2.set_ylabel('y')
    ax2.grid(True, linestyle='--', alpha=0.7)  # 显示网格
    ax2.legend()
    ax2.set_ylim(0, 1.2)  # 调整 y 轴范围匹配示例

    # 调整子图间距
    plt.tight_layout()
    # plt.show()
    st.pyplot(fig)


def softmax_run():
    def softmax(x):
        val = np.exp(x)
        return val / np.sum(val)

    def d_softmax(x):
        """
        np.diagflat() 这个函数的基本用法：传入一个一维数组，输出以该数组为对角线的平铺对角矩阵
        eg:
            arr = np.array([1, 2, 3])
            brr = np.diagflat(arr)
            print(brr.shape)       # (3, 3)
            print(brr)
            [
                [1, 0, 0],
                [0, 2, 0],
                [0, 0, 3]
            ]
        """
        s = softmax(x)
        return np.diagflat(s) - np.outer(s, s)

    """ 进行画图 """
    x = np.linspace(-5, 5, 100)
    y = softmax(x)
    dy = d_softmax(x)
    plt.subplot(121)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.plot(x, y)

    plt.subplot(122)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.plot(x, dy)

    # plt.show()
    st.pyplot(plt)


def sigmoid_code():
    sample_code = """
    import numpy as np
    import matplotlib.pyplot as plt
    def sigmoid(x):
        return 1 / (1 + np.exp(-x))

    def d_sigmoid(x):
        return sigmoid(x) * (1 - sigmoid(x))

    # 进行画图 
    x = np.linspace(-5, 5, 100)
    y = sigmoid(x)
    dy = d_sigmoid(x)
    plt.subplot(121)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.yticks(np.arange(0, 1.1, 0.1))
    plt.ylim(0, 1)
    plt.plot(x, y)
    plt.plot([0, 0], [0, 1], color="black", linewidth="2")

    plt.subplot(122)
    plt.xticks(np.arange(-5, 6, 1))
    plt.xlim(-5, 5)
    plt.yticks(np.arange(0, 1.1, 0.1))
    plt.ylim(0, 1)
    plt.plot(x, dy)
    plt.plot([0, 0], [0, 1], color="black", linewidth="2")

    plt.show()
    """
    return sample_code


def tanh_code():
    sample_code = """
import numpy as np
import matplotlib.pyplot as plt


def tanh(x):
    # return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))
    return np.tanh(x)

def d_tanh(x):
    return 1 - np.square(tanh(x))


# 进行画图 
x = np.linspace(-5, 5, 100)
y = tanh(x)
dy = d_tanh(x)
plt.subplot(121)
plt.xticks(np.arange(-5, 6, 1))
plt.xlim(-5, 5)
plt.yticks(np.arange(-1, 1.1, 0.1))
plt.ylim(-1, 1)
plt.plot(x, y)
plt.plot([0, 0], [-1, 1], color="black", linewidth="2")

plt.subplot(122)
plt.xticks(np.arange(-5, 6, 1))
plt.xlim(-5, 5)
plt.yticks(np.arange(0, 1.1, 0.1))
plt.ylim(0, 1)
plt.plot(x, dy)
plt.plot([0, 0], [0, 1], color="black", linewidth="2")

plt.show()
    """
    return sample_code


def relu_code():
    sample_code = """
# 定义两种ReLU函数
def linear_relu(x):
    # 线性ReLU：x≥0时输出x，x<0时输出0
    return np.maximum(0, x)

def binary_relu(x, threshold=0):
    # 二值化ReLU：x>threshold时输出1，否则输出0
    return np.where(x > threshold, 1, 0)

# 生成输入数据
x = np.linspace(-3, 3, 1000)  # 输入范围：-3到3
y_linear = linear_relu(x)
y_binary = binary_relu(x)

# 创建画布和子图（1行2列布局）
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# 绘制左侧：线性ReLU
ax1.plot(x, y_linear, color='royalblue', linewidth=2.5)
ax1.axhline(y=0, color='gray', linestyle='--', alpha=0.5)
ax1.axvline(x=0, color='gray', linestyle='--', alpha=0.5)
ax1.set_title('线性ReLU函数', fontsize=15)
ax1.set_xlabel('输入 x', fontsize=12)
ax1.set_ylabel('输出 y', fontsize=12)
ax1.set_ylim(-0.5, 3.5)  # 调整y轴范围，便于观察
ax1.grid(True, alpha=0.3)
ax1.text(1, 2.5, r'$y = \max(0, x)$', fontsize=14, color='royalblue')

# 绘制右侧：二值化ReLU
ax2.step(x, y_binary, color='crimson', linewidth=2.5, where='post')
ax2.axhline(y=0, color='gray', linestyle='--', alpha=0.5)
ax2.axvline(x=0, color='gray', linestyle='--', alpha=0.5)
ax2.set_title('二值化ReLU函数', fontsize=15)
ax2.set_xlabel('输入 x', fontsize=12)
ax2.set_ylabel('输出 y', fontsize=12)
ax2.set_ylim(-0.5, 1.5)  # 调整y轴范围，便于观察
ax2.grid(True, alpha=0.3)
ax2.text(1, 1.2, r'$y = 1\ \text{if}\ x>0,\ \text{else}\ 0$', fontsize=14, color='crimson')

# 调整布局并显示
plt.tight_layout()
plt.show()

    """
    return sample_code

def elu_code():
    sample_code = """
# 定义 ELU 函数
def elu(x, alpha=1.0):
    return np.where(x >= 0, x, alpha * (np.exp(x) - 1))

# 定义 ELU 导数
def elu_derivative(x, alpha=1.0):
    return np.where(x >= 0, 1, alpha * np.exp(x))

# 生成数据
x = np.linspace(-10, 10, 1000)
y_elu = elu(x)
y_deriv = elu_derivative(x)

# 创建并排子图（1 行 2 列）
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))  # 调整 figsize 控制整体大小

# 绘制 ELU 函数（上图）
ax1.plot(x, y_elu, color='blue', label='elu')
ax1.set_title('elu')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.grid(True, linestyle='--', alpha=0.7)  # 显示网格
ax1.legend()
ax1.set_ylim(-2, 10)  # 调整 y 轴范围匹配示例

# 绘制 ELU 导数（下图）
ax2.plot(x, y_deriv, color='blue', label='elu_derivative')
ax2.set_title('elu derivative')
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.grid(True, linestyle='--', alpha=0.7)  # 显示网格
ax2.legend()
ax2.set_ylim(0, 1.2)  # 调整 y 轴范围匹配示例

# 调整子图间距
plt.tight_layout()
plt.show()
    """
    return sample_code

def softmax_code():
    sample_code = """
def softmax(x):
    val = np.exp(x)
    return val / np.sum(val)

def d_softmax(x):
   
    # np.diagflat() 这个函数的基本用法：传入一个一维数组，输出以该数组为对角线的平铺对角矩阵
    # eg:
    #     arr = np.array([1, 2, 3])
    #     brr = np.diagflat(arr)
    #     print(brr.shape)       # (3, 3)
    #     print(brr)
    #     [
    #         [1, 0, 0],
    #         [0, 2, 0],
    #         [0, 0, 3]
    #     ]

    s = softmax(x)
    return np.diagflat(s) - np.outer(s, s)


# 进行画图 
x = np.linspace(-5, 5, 100)
y = softmax(x)
dy = d_softmax(x)
plt.subplot(121)
plt.xticks(np.arange(-5, 6, 1))
plt.xlim(-5, 5)
plt.plot(x, y)

plt.subplot(122)
plt.xticks(np.arange(-5, 6, 1))
plt.xlim(-5, 5)
plt.plot(x, dy)

plt.show()

    """
    return sample_code